package org.tcx.common.json;

import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Formatter;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

public class JsonUtil {
	public static void toJsonStr(Object obj,Writer writer) throws IOException {
		toJsonStr(obj, new HashSet<Object>(),writer);
	}

	private static void toJsonStr(Object obj, Set<Object> set,Writer writer) throws IOException {
		if (null == obj) {
			return;
		}
		set.add(obj);
		if (obj instanceof String) {
			writer.write("\"" + obj.toString() + "\"");
			return;
		}
		if (obj instanceof Boolean) {
			writer.write(obj.toString());
			return;
		}
		if (obj instanceof Number) {
			writer.write(obj.toString());
			return;
		}
		if (obj instanceof Date||obj instanceof Calendar) {
			Formatter formatter =new Formatter();
			JsonUtil.toJsonStr(formatter.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS", obj).toString(),set,writer);
			return ;
		}
		if (obj instanceof Collection) {
			Object[] objs = ((Collection<?>) obj).toArray();
			JsonUtil.toJsonStr(objs,set, writer);
			return;
		}
		if (obj.getClass().isArray()) {
			writer.write("[");
			int length = Array.getLength(obj);
			for (int i = 0; i < length; i++) {
				JsonUtil.toJsonStr(Array.get(obj, i),set,writer);
				if(length-1!=i){
					writer.write(",");
				}
			}
			writer.write("]");
			return;
		}
		if (obj instanceof Map) {
			Map<? , ?> obj_map = (Map<?, ?>) obj;
			writer.write("{");
			Entry<?,?>[] entries = obj_map.entrySet().toArray(new Entry<?,?>[0]);
			int length = entries.length;
			for (int i = 0; i < length; i++) {
				JsonUtil.toJsonStr(entries[i].getKey(),set,writer);
				writer.write(":");
				JsonUtil.toJsonStr(entries[i].getValue(),set,writer);
				if(length-1!=i){
					writer.write(",");
				}
			}
			writer.write("}");
			return ;
		}

		
		writer.write("{");
		Class<?> claz = obj.getClass();
		Field[] fields = claz.getDeclaredFields();
		boolean hasElement = false;
		for (Field field : fields) {
			JsonIgnore configFiled = field.getAnnotation(JsonIgnore.class);
			if (null == configFiled) {
				JsonFormatter formatter = field
						.getAnnotation(JsonFormatter.class);
				String filedName = field.getName();
				Object filedValue = ReflectUtil.getFiled(field, obj);
				if (null != formatter) {
					if (null != filedValue && !set.contains(filedValue)) {
						Formatter formatter2 = new Formatter();
						filedValue = formatter2.format(formatter.format(),
								filedValue).toString();
					}
				}
				if (null != filedValue && !isdup(set,filedValue)) {
					if(hasElement){
						writer.write(",");
					}
					JsonUtil.toJsonStr(filedName,set,writer);
					writer.write(":");
					JsonUtil.toJsonStr(filedValue,set,writer);
					hasElement =true;
				}
			}
		}
		writer.write("}");
		return;
	}

	private static boolean isdup(Set<Object> set, Object obj) {
		if (obj instanceof String) {
			return false;
		}
		if (obj instanceof Number) {
			return false;
		}
		if (obj instanceof Date||obj instanceof Calendar) {
			return false;
		}
		return set.contains(obj);
	}
}
